package Modelo;

import VO.VOMensaje;

public class Encriptador {
    VOMensaje claro;
    String clave;
    String [] subclaves;

    public Encriptador(VOMensaje m, String clave) {
        this.claro=m;
        this.clave = clave;
        this.subclaves = new String[16];
    }

    public VOMensaje Encriptar() {
        String tc="", tb="", teh="", tef="", iv="", tax="", tdx="";
        String [] teb;
        int lt,nb;
        VOMensaje enc=new VOMensaje();
        lt = this.claro.getMsj().length();
        this.GeneraSubClaves();
        nb = (int)lt/8;
        if(nb*8<lt)
            nb++;
        teb = new String[nb*8];
        for(int i=0; i<8; i++) {
            iv+=this.toBinario(this.clave.charAt(i));
        }
        
        for(int j=0; j<nb; j++) {
            if(j==0) {
                tax = this.Ronda(iv); System.out.println("iv: "+iv);
            } else {
                tax = this.Ronda(tdx); System.out.println("cfb: "+tdx);
            }
            if(j<nb-1)
                tc=this.claro.getMsj().substring(j*8,(j+1)*8);
            else
                tc=this.claro.getMsj().substring(j*8, lt);
            for(int i=0; i<8; i++) {
                if(i<tc.length())
                    tb+=this.toBinario(tc.charAt(i));
                else
                    tb+="00000000";
            }
            System.out.println("tax: "+tax);
            tdx=this.XOR(tax, tb);
            System.out.println("tb : "+tb);
            System.out.println("tdx: "+tdx);
            for(int i=0; i<8; i++) {
                teb[i+(8*j)]=tdx.substring(8*i, 8*(i+1));
            }
            tb=tc="";
        }
        for(int i=0; i<teb.length; i++) {
            teh+=this.intHex(this.BinariotoInt(teb[i]));
            tef+=teb[i];
        }
        System.out.println("tef: "+tef);
        enc.setEmisor(this.claro.getEmisor());
        enc.setReceptor(this.claro.getReceptor());
        enc.setMsj(tef);
        return enc;
    }

    public void GeneraSubClaves() {
        String Bclave="";
        String C, D, K;
        for(int i=0; i<this.clave.length(); i++) {
            Bclave+=this.toBinario(this.clave.charAt(i)).substring(0, 7)+"-";
        }
        Bclave = this.Permutar(Bclave, 1);
        C = Bclave.substring(0, 28);
        D = Bclave.substring(28, Bclave.length());
        for(int i=0; i<16; i++) {
            C = this.Rotacion(C, i);
            D = this.Rotacion(D, i);
            K = C+D;
            this.subclaves[i] = this.Permutar(K, 2);
//            System.out.println("subclave "+i+": "+this.subclaves[i]);
        }
    }

    public String Rotacion(String c, int r) {
        String s;
        int [] desp={1,1,2,2,2,2,2,2,1,2,2,2,2,2,2,1};
        s = c.substring(desp[r],c.length())+c.substring(0, desp[r]);
        return s;
    }

    public String Ronda(String c) {
        String s="",pi,L,R,Ls,Rs,B,Ba="";
        pi = this.Permutar(c, 3);
        L = pi.substring(0, 32);
        R = pi.substring(32, pi.length());
//        System.out.println("texto: "+c);
//        System.out.println("L: "+L);
//        System.out.println("R: "+R);
        for(int i=0; i<16; i++) {
            Ls = R;
            R = this.Permutar(R, 4);
//            System.out.println("Rexp: "+R);
            R = this.XOR(R, this.subclaves[i]);
//            System.out.println("XOR: "+R);
            for(int j=0; j<8; j++) {
                B=R.substring(6*j, 6*(j+1));
                Ba+=this.CajaS(B, j);
            }
//            System.out.println("Caja-S: "+Ba);
            Ba = this.Permutar(Ba, 5);
//            System.out.println("Per: "+Ba);
            R = this.XOR(L, Ba);
            L = Ls;
            Ba = "";
//            System.out.println("L("+(i+1)+"): "+L);
//            System.out.println("R("+(i+1)+"): "+R);
        }
//        System.out.println("R+L: "+R+L);
        s = this.Permutar(R+L, 6);
        return s;
    }

    public String XOR(String a, String b){
        String s="";
        for(int i=0; i<a.length(); i++){
            s +=a.charAt(i)^b.charAt(i);
        }
        return s;
    }

    public String CajaS(String e, int b) {
        String r="";
        int S[][] = {
            {14,4,13,1,2,15,11,8,3,10,6,12,5,9,0,7},
            {0,15,7,4,14,2,13,1,10,6,12,11,9,5,3,8},
            {4,1,14,8,13,6,2,11,15,12,9,7,3,10,5,0},
            {15,12,8,2,4,9,1,7,5,11,3,14,10,0,6,13},

            {15,1,8,14,6,11,3,4,9,7,2,13,12,0,5,10},
            {3,13,4,7,15,2,8,14,12,0,1,10,6,9,11,5},
            {0,14,7,11,10,4,13,1,5,8,12,6,9,3,2,15},
            {13,8,10,1,3,15,4,2,11,6,7,12,0,5,14,9},

            {10,0,9,14,6,3,15,5,1,13,12,7,11,4,2,8},
            {13,7,0,9,3,4,6,10,2,8,5,14,12,11,15,1},
            {13,6,4,9,8,15,3,0,11,1,2,12,5,10,14,7},
            {1,10,13,0,6,9,8,7,4,15,14,3,11,5,2,12},

            {7,13,14,3,0,6,9,10,1,2,8,5,11,12,4,15},
            {13,8,11,5,6,15,0,3,4,7,2,12,1,10,14,9},
            {10,6,9,0,12,11,7,13,15,1,3,14,5,2,8,4},
            {3,15,0,6,10,1,13,8,9,4,5,11,12,7,2,14},

            {2, 12,4, 1, 7, 10,11,6, 8, 5, 3, 15,13,0, 14,9},
            {14,11,2, 12,4, 7, 13,1, 5, 0, 15,10,3, 9, 8, 6},
            {4, 2, 1, 11,10,13,7, 8, 15,9, 12,5, 6, 3, 0, 14},
            {11,8, 12,7, 1, 14,2, 13,6, 15,0, 9, 10,4, 5, 3},

            {12,1, 10,15,9, 2, 6, 8, 0, 13,3, 4, 14,7, 5, 11},
            {10,15,4, 2, 7, 12,9, 5, 6, 1, 13,14,0, 11,3, 8},
            {9, 14,15,5, 2, 8, 12,3, 7, 0, 4, 10,1, 13,11,6},
            {4, 3, 2, 12,9, 5, 15,10,11,14,1, 7, 6, 0, 8, 13},

            {4, 11,2, 14,15,0, 8, 13,3, 12,9, 7, 5, 10,6, 1},
            {13,0, 11,7, 4, 9, 1, 10,14,3, 5, 12,2, 15,8, 6},
            {1, 4, 11,13,12,3, 7, 14,10,15,6, 8, 0, 5, 9, 2},
            {6, 11,13,8, 1, 4, 10,7, 9, 5, 0, 15,14,2, 3, 12},

            {13,2, 8, 4, 6, 15,11,1, 10,9, 3, 14,5, 0, 12,7},
            {1, 15,13,8, 10,3, 7, 4, 12,5, 6, 11,0, 14,9, 2},
            {7, 11,4, 1, 9, 12,14,2, 0, 6, 10,13,15,3, 5, 8},
            {2, 1, 14,7, 4, 10,8, 13,15,12,9, 0, 3, 5, 6, 11}};
        int f, c, l;
        f = this.BinariotoInt(e.substring(0,1)+e.substring(e.length()-1, e.length()));
        c = this.BinariotoInt(e.substring(1,e.length()-1));
        r=Integer.toBinaryString(S[f+(b*4)][c]);
        l=r.length();
        if(l<4) {
            for(int i=0; i<4-l; i++) {
                r="0"+r;
            }
        }
        return r;
    }
    public String Permutar(String n, int t) {
        String p="";
        int [] cp = null;
        switch (t) {
            case 1:
                cp = new int[]{57,49,41,33,25,17,9,1,58,50,42,34,26,18,10,2,59,51,43,35,27,19,11,3,60,52,44,36,63,55,47,39,31,23,15,7,62,54,46,38,30,22,14,6,61,53,45,37,29,21,13,5,28,20,12,4};
                break;
            case 2:
                cp = new int[]{14,17,11,24,1,5,3,28,15,6,21,10,23,19,12,4,26,8,16,7,27,20,13,2,41,52,31,37,47,55,30,40,51,45,33,48,44,49,39,56,34,53,46,42,50,36,29,32};
                break;
            case 3:
                cp = new int[]{58,50,42,34,26,18,10,2,60,52,44,36,28,20,12,4,62,54,46,38,30,22,14,6,64,56,48,40,32,24,16,8,57,49,41,33,25,17,9,1,59,51,43,35,27,19,11,3,61,53,45,37,29,21,13,5,63,55,47,39,31,23,15,7};
                break;
            case 4:
                cp = new int[]{32,1,2,3,4,5,4,5,6,7,8,9,8,9,10,11,12,13,12,13,14,15,16,17,16,17,18,19,20,21,20,21,22,23,24,25,24,25,26,27,28,29,28,29,30,31,32,1};
                break;
            case 5:
                cp = new int[]{16,7,20,21,29,12,28,17,1,15,23,26,5,18,31,10,2,8,24,14,32,27,3,9,19,13,30,6,22,11,4,25};
                break;
            case 6:
                cp = new int[]{40,8,48,16,56,24,64,32,39,7,47,15,55,23,63,31,38,6,46,14,54,22,62,30,37,5,45,13,53,21,61,29,36,4,44,12,52,20,60,28,35,3,43,11,51,19,59,27,34,2,42,10,50,18,58,26,33,1,41,9,49,17,57,25};
                break;
        }
        for(int i=0; i<cp.length; i++) {
            p+=n.charAt(cp[i]-1)+"";
        }
        return p;
    }

    
    public String toBinario(char t) {
        String s;
        int l;
        s=Integer.toBinaryString(t);
        l=s.length();
        if(l<8) {
            for(int i=0; i<8-l; i++) {
                s="0"+s;
            }
        }
        return s;
    }

    public int BinariotoInt(String n) {
        int r=0;
        int l=n.length();
        for(int i=0; i<l; i++) {
            r += Integer.parseInt(n.substring(i,i+1))*Math.pow(2,l-i-1);
        }
        return r;
    }

    public String intHex(int n) {
        String s;
        int l;
        s=Integer.toHexString(n);
        l=s.length();
        if(l<2) {
            for(int i=0; i<2-l; i++) {
                s="0"+s;
            }
        }
        return s.toUpperCase();
    }
}

